﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using Evaluant.PS4VS.Renderer;
using System.Drawing.Drawing2D;
using System.Threading;

namespace Evaluant.PS4VS
{
    public partial class ConsoleControl : Control
    {
        public ConsoleControl()
        {
            BackColor = Color.Black;
            ForeColor = Color.White;
            f = new Font(FontFamily.GenericMonospace, 10, FontStyle.Bold);
            charactersSize = new SizeF(10, f.GetHeight());
            content = new CharToDisplay[300][];
        }

        Font f;

        CharToDisplay[][] content;

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            base.OnKeyPress(e);
        }

        bool dirtyContent = false;
        bool dirtyScroll = false;
        string previousContent;

        protected SizeF charactersSize;

        public Size SizeInCharacters
        {
            get
            {
                if (charactersSize.IsEmpty)
                    return charactersSize.ToSize();
                Size size = charactersSize.ToSize();
                return new Size(Size.Width / size.Width, Size.Height / size.Height);
            }
        }

        public int LineCount { get; protected set; }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (charactersSize.IsEmpty)
                charactersSize = pe.Graphics.MeasureString("A", f).ToSize();
            if (dirtyScroll)
            {
                SizeF size = pe.Graphics.MeasureString(previousContent, f);
                if (!charactersSize.IsEmpty)
                    LineCount = (int)(size.Height / charactersSize.Height);
                if (Size.Subtract(base.Size, size.ToSize()).Height < 0)
                {
                    if (LineCount > 0)
                        this.AutoScrollOffset = new Point(0, Math.Min(pe.ClipRectangle.Height - size.ToSize().Height, 0) / LineCount);
                    this.Size = new Size(Width, size.ToSize().Height);
                    dirtyScroll = false;
                }
            }
            PointF origin = new PointF(AutoScrollOffset.X * charactersSize.Width, AutoScrollOffset.Y * (f.GetHeight()));
            GraphicsContainer container = pe.Graphics.BeginContainer();
            pe.Graphics.SmoothingMode = SmoothingMode.None;
            pe.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
            pe.Graphics.TextContrast = 0;
            pe.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;

            for (int y = 0; y < content.Length; y++)
            {
                if (content[y] == null)
                    break;
                PointF charPosition = new PointF(origin.X, origin.Y + y * f.GetHeight());
                if (!pe.ClipRectangle.Contains(new Point((int)charPosition.X, (int)charPosition.Y)))
                    continue;
                for (int x = 0; x < content[y].Length; x++)
                {
                    charPosition.X += 8;
                    CharToDisplay c = content[y][x];
                    pe.Graphics.DrawString(c.Char.ToString(), f, new SolidBrush(c.ForeColor), charPosition);
                }
            }
            pe.Graphics.EndContainer(container);
            //pe.Graphics.DrawString(previousContent, f, Brushes.White, new PointF(AutoScrollOffset.X * charactersSize.Width, AutoScrollOffset.Y * (f.GetHeight())));
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);
            dirtyScroll = true;
            Refresh();
        }

        public int CurrentLine { get; protected set; }

        StringBuilder lineBuilder = new StringBuilder(80);

        private void WaitForOtherOutputBeforeRefresh()
        {
            dirtyContent = false;
            Thread.Sleep(500);
            if (dirtyContent)
                return;
            Invoke(new Action(Refresh));
            BeginInvoke(new Action(((MyControl)Parent).RefreshScroll));
        }


        public void Write(string s)
        {
            lineBuilder.Append(s);
            if (!s.Contains('\n'))
                return;
            content[CurrentLine] = new CharToDisplay[Math.Min(lineBuilder.Length, 80)];
            dirtyContent = true;
            dirtyScroll = true;
            for (int i = 0; i < lineBuilder.Length; i++)
            {
                content[CurrentLine][i] = s[i];
                if (lineBuilder[i] == '\n')
                {
                    CurrentLine++;
                    lineBuilder = new StringBuilder(80);
                }
            }
            new Action(WaitForOtherOutputBeforeRefresh).BeginInvoke(null, null);
        }

        public void Write(string s, params object[] args)
        {
            Write(string.Format(s, args));
        }

        public void WriteLine(string s)
        {
            Write(s + "\n");
        }

        public void WriteLine(string s, params object[] args)
        {
            WriteLine(string.Format(s, args));
        }

        internal string ReadLine()
        {
            throw new NotImplementedException();
        }
    }
}
